package com.navi.loaddata.loadService.impl.hisData.cell2;

import com.navi.loaddata.core.errorLog.ErrorLog;
import com.navi.loaddata.core.etlException.ETLException;
import com.navi.loaddata.core.mesEntity.MesProducthistory;
import com.navi.loaddata.core.mysqlEntity.EtlConfD;
import com.navi.loaddata.core.oracleEntity.cell2.EtlCell2CmnChipV;
import com.navi.loaddata.core.oracleEntity.cell2.EtlCell2ChipHstV;
import com.navi.loaddata.core.oracleEntity.cell2.EtlCell2ProductV;
import com.navi.loaddata.core.oracleEntity.cell2.EtlCell2StepV;
import com.navi.loaddata.core.repository.impl.OracleRepositoryImpl;
import com.navi.loaddata.core.util.LoggerUtil;
import com.navi.loaddata.core.util.ProcessUtil;
import com.navi.loaddata.loadService.impl.baseData.cell2.LoadMesBaseDataServiceCELL2;
import com.navi.loaddata.loadService.impl.baseData.cell2.ProcessBaseDataServiceCELL2;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.navi.loaddata.core.constant.GenericDef.SHOP_OC;
import static java.util.stream.Collectors.groupingBy;

/**
 * @author jay
 */
@Service
@Transactional(transactionManager = "thirdaryPlatformTransactionManager",
        rollbackFor = {RuntimeException.class, Exception.class})
public class LoadHisDataServiceCELL2 {
    private static final Logger logger = LoggerFactory.getLogger(LoadHisDataServiceCELL2.class);
    private LoggerUtil loggerUtil = new LoggerUtil(this.getClass());

    @Autowired
    private OracleRepositoryImpl dao3;

    @Autowired
    private LoadMesBaseDataServiceCELL2 loadMesBaseDataService;

    @Autowired
    private ProcessBaseDataServiceCELL2 processBaseDataService;
    @Autowired
    private ProcessHisDataServiceCELL2 processHisDataService;
    @Autowired
    private LoadHisInfoServiceCELL2 loadHisInfoService;


    public int loadHisDataMain(EtlConfD etlConfD) throws ETLException {
        int countSize = 0;
        Session session = dao3.getEntityManagerSession();
        try {
            countSize = loadHisData(session, etlConfD);
            logger.info("LoadHisDataMain finish");
        } catch (ETLException e) {
//            logger.error(LoggerUtil.stackTraceToString(e));
            //todo test rollback
            throw new ETLException(e.getMessage());
        }
        return countSize;
    }

    /**
     * Load Teg Data
     * <p>
     * load base -> session table
     * load defect data  -> session table
     * call base proc  -> auto commit
     * call defect proc -> no auto commit
     * delete defect session table
     *
     * @param session
     * @param etlConfD
     */
    private int loadHisData(Session session, EtlConfD etlConfD) throws ETLException {//***
        int countSize = 0;


        List<MesProducthistory> hisTrackOut = loadHisInfoService.loadHisOutInfo(etlConfD);
        logger.info("CELL2 His glass count {}", hisTrackOut.size());
        String hisTrackInKey = getGlassInCondition(hisTrackOut);
        if (!hisTrackOut.isEmpty()) {
            Map<String, MesProducthistory> hisTrackIn = loadHisInfoService.loadHisInInfo(etlConfD, hisTrackInKey);
            // base
            List<EtlCell2StepV> etlCellStepVList = new ArrayList<>();
            List<EtlCell2ProductV> etlCellProductVList = new ArrayList<>();
            try {
                etlCellStepVList = loadMesBaseDataService.loadAllFinalStep(SHOP_OC, ErrorLog.ERROR_PROCESS_ARRAY_STEP_V);
                etlCellProductVList = loadMesBaseDataService.loadAllFinalProduct(SHOP_OC, ErrorLog.ERROR_PROCESS_ARRAY_PRODUCT_V);
            } catch (Exception e) {
                logger.error("Cannot excute loadAll()_BASE from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                throw new ETLException(e.getMessage());
            }
            // save base
            try {
                saveAll(etlCellStepVList, ErrorLog.ERROR_TABLE_ETL_ARRAY_STEP_V, "NULL");
                saveAll(etlCellProductVList, ErrorLog.ERROR_TABLE_ETL_ARRAY_PRODUCT_V, "NULL");
            } catch (Exception e) {
                logger.error("Cannot excute dao.saveAll()_BASE from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                throw new ETLException(e.getMessage());
            }

            // call base proc
            try {
                SQLQuery queryLoadStep = session.createSQLQuery("{call CELL2_BASE_LOADER.LOAD_STEP()}");
                queryLoadStep.executeUpdate();
            } catch (Exception e) {
                logger.error(e.getMessage());
                logger.error(LoggerUtil.stackTraceToString(e));
                logger.error("Cannot call procedure from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                throw new ETLException("ALL" + ErrorLog.ERROR_LOAD_ARRAY_STEP_V + e.getMessage());
            }
            try {
                SQLQuery queryLoadProduct = session.createSQLQuery("{call CELL2_BASE_LOADER.LOAD_PRODUCT()}");
                queryLoadProduct.executeUpdate();
            } catch (Exception e) {
                logger.error(e.getMessage());
                logger.error(LoggerUtil.stackTraceToString(e));
                logger.error("Cannot call procedure from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                throw new ETLException("ALL" + ErrorLog.ERROR_LOAD_ARRAY_PRODUCT_V + e.getMessage());
            }

            Map<String, List<MesProducthistory>> hisDataTree =
                    hisTrackOut.stream().collect(groupingBy(MesProducthistory::getProductname));
            for (Map.Entry<String, List<MesProducthistory>> entry : hisDataTree.entrySet()) {
                List<MesProducthistory> curHisList = entry.getValue();
                //common
                List<MesProducthistory> commonGlassVList =
                        loadMesBaseDataService.loadCommonGlassInfo(etlConfD, curHisList.get(0).getProductname());
                if (commonGlassVList.size() == 0) {
//                    System.out.println("+++++++++++++++++");
                    continue;
                }
//                System.out.println("===========================");
                List<EtlCell2CmnChipV> etlArrayCommonGlassVList = new ArrayList<>();
                try {
                    etlArrayCommonGlassVList = processBaseDataService.processCommonGlass(commonGlassVList, ErrorLog.ERROR_PROCESS_ARRAY_CMN_GLASS_V);
                } catch (Exception e) {
                    logger.error("Cannot excute processCMN() from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                    throw new ETLException(curHisList.get(0).getProductname() + ":" + e.getMessage());
                }
//                logger.info("Array common glass count {}", commonGlassVList.size());
                // save
                try {
                    saveAll(etlArrayCommonGlassVList, ErrorLog.ERROR_TABLE_ETL_ARRAY_CMN_GLASS_V, curHisList.get(0).getProductname());
                } catch (Exception e) {
                    logger.error("Cannot excute dao.saveCMN() from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                    throw new ETLException(e.getMessage());
                }
                // call procedure
                try {
                    SQLQuery queryLoadCmnGlass = session.createSQLQuery("{call CELL2_MES_LOADER.LOAD_CMN_CHIP()}");
                    queryLoadCmnGlass.executeUpdate();
                } catch (Exception e) {
                    logger.error(LoggerUtil.stackTraceToString(e));
                    logger.error("Cannot call procedure from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                    throw new ETLException(curHisList.get(0).getProductname() + ":" + ErrorLog.ERROR_LOAD_ARRAY_CMN_GLASS_V + ":" + e.getMessage());
                }

                // His
                for (int i = 0; i < curHisList.size(); i++) {
                    //站点限制
                    if (true == (ProcessUtil.opeLimit(curHisList.get(i).getOldprocessoperationname()))) {
                        continue;
                    }
                    //LINKKEY IS NULL
                    if(StringUtils.isEmpty(curHisList.get(i).getLinkkey())){
                        continue;
                    }

                    //process
                    List<EtlCell2ChipHstV> etlCellComponentHstVList = new ArrayList<>();
                    try {
                        etlCellComponentHstVList = processHisDataService.processHis(hisTrackIn, curHisList.get(i), ErrorLog.ERROR_PROCESS_ARRAY_GLASS_HST_V);
                    } catch (Exception e) {
                        logger.error("Cannot excute process() from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                        throw new ETLException("process错误：" + curHisList.get(i).getProductname() + ":" + e.getMessage());
                    }
//
                    // save
                    try {
                        saveAll(etlCellComponentHstVList, ErrorLog.ERROR_TABLE_ETL_ARRAY_GLASS_HST_V, curHisList.get(i).getProductname());
                    } catch (Exception e) {
                        logger.info("Cannot excute dao.saveAll() from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                        throw new ETLException(e.getMessage());
                    }

                    // call proc
                    try {
                        SQLQuery queryDefect = session.createSQLQuery("{Call CELL2_MES_LOADER.LOAD_CHIP_HST()}");
                        queryDefect.executeUpdate();
                    } catch (Exception e) {
                        logger.error(ErrorLog.ERROR_LOAD_ARRAY_GLASS_HST_V + ":" + e.getMessage());
                        logger.error(LoggerUtil.stackTraceToString(e));
                        logger.error("Cannot call procedure from [{}] to [{}]。", etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp());
                        throw new ETLException(curHisList.get(i).getProductname() + ":" + ErrorLog.ERROR_LOAD_ARRAY_GLASS_HST_V + ":" + e.getMessage());
                    }

                    countSize++;
                    try {
                        String hqlHis = "Delete FROM EtlCell2ChipHstV";
//                        String hqlCMN = "Delete FROM EtlCell2CmnChipV";
                        Query qHis = session.createQuery(hqlHis);
//                        Query qCMN = session.createQuery(hqlCMN);
                        qHis.executeUpdate();
//                        qCMN.executeUpdate();
//                        logger.info("删除HIS_ETL成功！");
                    } catch (Exception e) {
                        logger.error(LoggerUtil.stackTraceToString(e));
                        throw new ETLException("删除HIS_ETL错误:" + e.getMessage());
                    }
//        测试
//        List test=dao3.find(EtlArrayGlassV.class,"from EtlCell2ChipHstVPK");
//        System.out.println("===="+test.size());
                }
                try {
                    String hqlCMN = "Delete FROM EtlCell2CmnChipV";
                    Query qCMN = session.createQuery(hqlCMN);
                    qCMN.executeUpdate();
//                    logger.info("删除CMN成功！");
                } catch (Exception e) {
                    logger.error(LoggerUtil.stackTraceToString(e));
                    throw new ETLException("删除CMN错误:" + e.getMessage());
                }
            }

        } else

        {
            logger.info("没有此区间的数据。"); // todo print log & save etl data
        }
        return countSize;
    }

    private String getGlassInCondition(List<MesProducthistory> curHisList) {
        StringBuffer glassIds = new StringBuffer();
        int size = curHisList.size();
        for (int i = 0; i < size; i++) {
            glassIds.append("('").append(curHisList.get(i).getProductname()).append("','").append(curHisList.get(i).getLinkkey()).append("')");
            if (i < size - 1) {
                glassIds.append(",");
            }
        }
        return glassIds.toString();
    }

    public <T> void saveAll(List<T> entities, int errorViewLog, String glassId) throws ETLException {
        try {
            dao3.saveAll(entities);
        } catch (Exception e) {
            logger.error(errorViewLog + ":" + e.getMessage());
            logger.error(LoggerUtil.stackTraceToString(e));
            throw new ETLException(glassId + ":" + errorViewLog + ":" + e.getMessage());
        }
    }
}
